#include "EmoRecogCore.h"

std::mutex EmoRecogCore::mutex_emoDataCpy;
#define FILT_TIME
#define GET_TIME
#define DEBUG

EmoRecogCore::EmoRecogCore(ConfigImport* sysconf, QObject* parent) : 
    QObject(parent),
    EmoRecBase(sysconf),
    workingMode(m_workingMode)
{
    m_workingMode = Free;
    networkCreate_enable = false;

}

EmoRecogCore::~EmoRecogCore()
{
    // m_workingMode = Free;


}

/**********************************
 * 函数名：run
 * 功能：情绪识别任务
 * 输入：无
 * 输出：无
 * 备注：无
**********************************/
void EmoRecogCore::run(){
    arma::mat data;
    int predictResult;
    switch (m_workingMode){
        case Free:
            break;
        case Train:
            if(networkCreate_enable){
                std::unique_lock<std::mutex> lock(mutex_emoDataCpy); // 加锁,自动释放
                network_created(train_data);

                auto BT_T = std::chrono::steady_clock::now();
                train();
                auto AT_T = std::chrono::steady_clock::now();
                double duration_millsecond = std::chrono::duration<double, std::milli>(AT_T - BT_T).count();
                std::cout << "train time :" << duration_millsecond << "ms" << std::endl; 
                networkCreate_enable = false;
                train_data.clear();
                m_workingMode = Free;
            }
            break;
        case Predict:
            data = arma::conv_to<arma::mat>::from(predict_data);
            predictResult = predict(data);
            // std::cout << "In EmoRecogCore::run(), predictResult=" << predictResult << std::endl; 
            if(predictResult == videoLabel){
                ++correctCount;
            }
            else{
                ++errorCount;
            }

            // std::cout << "correctCount:" << correctCount << " errorCount:" << errorCount << std::endl;
            // std::cout << "predict acc:" << correctCount / (float)(correctCount+errorCount) * 100 << "%" << std::endl;

            emit send_predictResult(predictResult);
            predict_data.clear();
        break;
        
        default:
            break;
    }

}

void EmoRecogCore::readyToCreateModel(){
    
}


void EmoRecogCore::showAcc(){
    float acc = (float)correctCount / (correctCount+errorCount);
    std::cout << "predict acc:" << acc * 100 << "%" << std::endl;
}


/**********************************
 * 函数名：receiveData
 * 功能：接收中转站的数据，进行处理
 * 输入：无
 * 输出：无
 * 备注：无
**********************************/
long long EmoRecogCore::receiveData(const arma::cube& data){
    long long recLen = 0;
    std::unique_lock<std::mutex> lock(mutex_emoDataCpy); // 加锁,自动释放
    switch (m_workingMode)
    {
        case Free:
            printf("EmoRecogCore is not working!\n");
            break;

        case Train:
        {
        #ifdef DEBUG
            printf("train task:receive data.\n");
        #endif // DEBUG
            
            if(!train_data.n_elem_slice){
                train_data = data;
                networkCreate_enable = true;
                break;
            }
            
            recLen = train_data.n_elem;
            networkCreate_enable = true;
            
            break;
        }

        case Predict:
        #ifdef DEBUG
            // printf("predict task:receive data.\n");
        #endif

            if(!predict_data.n_elem){
                predict_data = data.slice(0).row(0);
                break;
            }
            recLen = predict_data.n_elem;
        
            break;
        
        default:
            break;
    }



    return recLen;    
}

/**********************************
 * 函数名：receiveData
 * 功能：接收一个trial的数据
 * 输入：GenEEGData& data：一帧数据
 * 输出：无
 * 备注：无
**********************************/
long long EmoRecogCore::receiveData(const GenEEGData &inputData){
    // std::cout << "In EmoRecogCore::receiveData(GenEEGData&)" << std::endl;
#ifdef FILT_TIME
    auto BT_rcData = std::chrono::steady_clock::now();
#endif
    // 数据不满一个trial，舍弃
    if(inputData.data.size() < sys_config.pointPerTrial) {
        static int erroTimes = 0;
        ++erroTimes;
        std::cout << "lost data times:" << erroTimes << std::endl;
        std::cout << "len:" << inputData.data.size() << std::endl;
        return -1;
    }

    arma::cube oneTrial(inputData.dataHead.channalNum, inputData.data.size(), 1);     // 64 * pointPerTrial * 1
    for (size_t i = 0; i < inputData.data.size(); ++i) {
        double* target_ptr = oneTrial.slice(0).colptr(i);
        std::memcpy(target_ptr, inputData.data[i].data(), EEGDataArr().size() * sizeof(double));
    }

    long long len = receiveData(oneTrial);

#ifdef FILT_TIME
    auto AT_rcData = std::chrono::steady_clock::now();
    double duration_millsecond = std::chrono::duration<double, std::milli>(AT_rcData - BT_rcData).count();
    std::cout << "In EmoRecogCore::receiveData, receive data time:" << duration_millsecond << "ms" << std::endl;
#endif

    return len;
}

void EmoRecogCore::slt_receivePredictData(const arma::rowvec &data){
    // std::cout << "In EmoRecogCore::slt_receivePredictData()" << std::endl;
    arma::cube oneTrial(data.n_rows, data.n_cols, 1);     // 1 * [channal*(channal-1)/2] * 1
    oneTrial.slice(0).row(0) = data;
    receiveData(oneTrial);
    run();
}

void EmoRecogCore::slt_receivePredictVideoLabel(EmotionInterface::EmoMode mode){
    videoLabel = mode;
    std::cout << "In EmoRecogCore::slt_receivePredictVideoLabel,current video label:" << videoLabel << std::endl;
}

void EmoRecogCore::clear(WorkingMode mode){
    switch (mode){
        case Free:
            train_data.clear();
            predict_data.clear();
        break;
        case Train:
            train_data.clear();
            break;
        case Predict:
            predict_data.clear();
        default:
            break;
    }
}
void EmoRecogCore::setWorkingMode(WorkingMode data){m_workingMode = data;}

